var Log = require('../../../util/logger');
var path = require('path');
var util = require('../../../util/index');
var notify = require('../../notify/ui');
var fs = require('fs');
var frac = require('../../../util/frac');
var config = require('../../../core/config');

var ret = {
    getNote: function(filepath){
        var raw = fs.readFileSync(filepath, {encoding:'utf8'});
        if(!raw){
            return null;
        }
        this.dir = path.dirname(filepath);
        var lines = raw.split(/\n|\r\n/g);
        var ret = {
            meta : {
                mode : 0,
                song : {}
            },
            time : [],
            note : [],
            extra : {
                samples : [],
                toggle : [0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]
            }
        };
        this.segment = null;
        this.offset = 0;
        this.offsetCorrection = 0; //osu的修正
        this.beatLen = 0;
        this.colSize = 0;
        this.colWidth = 0;
        this.divide = 24;
        this.sampleMapping = {};
        this.samples = ["", "normal", "soft", "drum"];
        this.sampleList = [];
        this.errorInfo = null;
        this.fileMapping = {};
        this.soundTrackMapping = {}; //用于记录某个轨道的某个位置是否被占用 key为beat-subbeat-column
        this.eventLines = [];
        if(lines[0].indexOf("osu file format") < 0){
            notify.addNotify({msg:config.i18n("osu01")});
            return ret;
        }
        //列出所有的素材 消除扩展名和大小写的影响 比如Sample.ogg SamPle.mp3 都可以通过sample找到
        var files = fs.readdirSync(this.dir);
        for(var i=0;i<files.length;i++){
            var realName = files[i];
            var name = realName.toLocaleLowerCase();
            var ext = path.extname(name);
            if(ext == ".mp3" || ext == ".ogg" || ext == ".wav"){
                this.fileMapping[path.basename(name, ext)] = realName;
            }
        }
        for(var i=0;i<lines.length;i++){
            var line = lines[i];
            if(line.length == 0 || line.indexOf("//") == 0){
                continue;
            }
            //判断是不是ini段头
            if(/^\[.*?\]/.test(line)){
                this.segment = line.substring(1, line.length-1);
                continue;
            }
            if(!this.parseRow(line, ret)){
                notify.addNotify({msg:this.errorInfo});
                break;
            }
        }
        var toggle = ret.extra.toggle;
        for(var i=0;i<this.colSize;i++){
            toggle[i] = 1;
        }
        toggle[this.colSize] = 2;
        this.parseEvents(ret);
        util.setJsonChainValue(ret, 'meta.mode_ext.column', this.colSize);
        // 如果bgm note的offset为负值 整体平移
        var bgmNote = ret.note[0];
        var bpm = ret.time[0].bpm;
        var beatTime = 60000/bpm;
        if(bgmNote.isBgm && bgmNote.offset < 0){
            var beatUp = Math.ceil(Math.abs(bgmNote.offset) / beatTime);
            bgmNote.offset += Math.round(beatTime * beatUp);
            for(var i=1;i<ret.note.length;i++){
                var rnote = ret.note[i];
                rnote.beat[0] = rnote.beat[0] + beatUp;
                if(rnote.endbeat){
                    rnote.endbeat[0] = rnote.endbeat[0] + beatUp;
                }
            }
        }
        return ret;
    },

    parseEvents : function(ret){
        for(var i=0;i<this.eventLines.length;i++){
            var obj = this.eventLines[i];
            var beat = this.getBeat(obj[1]);
            var fn = obj[3].replace(/"/g,"");
            var realSound = this.getRealSample(fn);
            var note = {
                sound : realSound,
                vol : +obj[4] || 30,
                type : 2,
                beat: beat,
                tid: this.getSampleId(realSound, ret)
            };
            var colStart = this.colSize + 1;
            while(colStart<15){
                //防止2个采样叠加到同一个note上
                var key = beat[0] + "_" + beat[1] + colStart;
                if(!this.soundTrackMapping[key]){
                    note.column = colStart;
                    ret.extra.toggle[note.column] = 2;
                    this.soundTrackMapping[key] = true;
                    break;
                }else{
                    colStart ++;
                }
            }
            ret.note.push(note);
        }
    },

    getValPair : function(line){
        var tmp = line.split(":");
        return [tmp[0].trim(), tmp[1].trim()];
    },

    getRealSample : function(fn){
        fn = fn.toLowerCase();
        var audio = path.basename(fn, path.extname(fn));
        return this.fileMapping[audio];
    },

    getSampleId : function(fn, ret){
        var tid = this.sampleMapping[fn];
        if(!tid){
            ret.extra.samples.push({
                name : fn
            });
            this.sampleMapping[fn] = ret.extra.samples.length;
        }
        return tid;
    },

    parseRow : function(line, ret){
        var segment = this.segment;
        if(segment == "General"){
            var pair = this.getValPair(line);
            if(pair[0] == "AudioFilename"){
                var audio = this.getRealSample(pair[1])
                ret.extra.samples.push({
                    name : audio
                });
                ret.note.push({
                    sound : audio,
                    type : 1,
                    isBgm : true,
                    beat: [0,0,4],
                    column: this.colSize,
                    offset : this.offset,
                    tid: 0
                });
            }else if(pair[0] == "OffsetCorrection"){
                this.offsetCorrection = parseInt(pair[1]);
            }else if(pair[0] == "Mode"){
                var mode = +pair[1];
                if(mode != 3){
                    this.errorInfo = config.i18n("osu03");
                    return false;
                }
            }
        }else if(segment == "TimingPoints"){
            var timing = line.split(",");
            if(timing[6] == 1){
                if(ret.time.length > 0){
                    this.errorInfo = config.i18n("osu02");
                    return false;
                }
                this.beatLen = +timing[1];
                ret.time.push({
                    "beat": [0,0,1],
                    "bpm": 60000 / this.beatLen,
                    "signature": 4,
                    "measure": [0,0,4],
                    "time": 0,
                    "vol": +timing[5]
                });
                this.offset = +timing[0];
                if(ret.note.length && ret.note[0].isBgm){
                    //修正bgm note的偏移
                    ret.note[0].offset = -1 * (this.offset + this.offsetCorrection) + 23;
                    ret.note[0].vol = +timing[5];
                }
                if(timing[3] != "0"){
                    this.sampleList.push({
                        offset: +timing[0],
                        sampleType: +timing[3],
                        sampleSet: +timing[4],
                        vol: +timing[5]
                    });
                }
            }
        }else if(segment == "Metadata"){
            var pair = this.getValPair(line);
            if(pair[0] == "Title") {
                ret.meta.song.title = pair[1];
            }else if(pair[0] == "TitleUnicode"){
                util.setJsonChainValue(ret, 'meta.song.org.title', pair[1]);
            }else if(pair[0] == "Artist") {
                ret.meta.song.artist = pair[1];
            }else if(pair[0] == "ArtistUnicode"){
                util.setJsonChainValue(ret, 'meta.song.org.artist', pair[1]);
            }else if(pair[0] == "Creator"){
                ret.meta.creator = pair[1];
            }else if(pair[0] == "Version"){
                ret.meta.version = pair[1];
            }else if(pair[0] == "Source"){
                ret.meta.song.source = pair[1];
            }
        }else if(segment == "Editor"){
            var pair = this.getValPair(line);
            if(pair[0] == "BeatDivisor"){
                //this.divide = +pair[1];
            }
        }else if(segment == "Difficulty"){
            var pair = this.getValPair(line);
            if(pair[0] == "CircleSize"){
                this.colSize = +pair[1];
                this.colWidth = parseInt(512 / this.colSize);
                //因为colsize比sample来得晚 这里要修正sample
                if(ret.note[0] && ret.note[0].isBgm){
                    ret.note[0].column = this.colSize;
                }
            }
        }else if(segment == "HitObjects"){
            var obj = line.split(",");
            var x = +obj[0];
            var col = Math.floor(x / this.colWidth);
            var snd = null;
            var note = {
                beat: this.getBeat(obj[2]),
                column: col,
                tid: -1
            }
            var vol = null;
            if(obj[5]){
                snd = this.getHitSound(obj, ret);
                if(snd && snd.vol){
                    vol = snd.vol;
                }
            }
            if(obj[3] & 128){
                var endStr = obj[5];
                if(obj[5].indexOf(":") > 0){
                    endStr = endStr.split(":")[0];
                }

                note.endbeat = this.getBeat(endStr);
            }
            if(snd){
                note.sound = snd.realFile;
                note.tid = snd.tid;
                //获取全局的音量
                var volTiming = this.getSampleByTime(obj[2]);
                if(volTiming){
                    volTiming = volTiming.vol;
                }
                note.vol = volTiming || vol || 30;
            }
            ret.note.push(note);
        }else if(segment == "Events"){
            var obj = line.split(",");
            if(obj[0] == "Sample"){
                //这里只能先存着 因为event来的时候没有bpm
                this.eventLines.push(obj);
            }
        }
        return true;
    },

    getSampleByTime : function(offset){
        var ret;
        for(var i=0;i<this.sampleList.length;i++){
            var tp = this.sampleList[i];
            if(offset > tp.offset){
                ret = tp;
            }else{
                break;
            }
        }
        return ret;
    },

    getHitSound : function(obj, ret){
        //先找到是不是属于某个timing区间

        var offset = +obj[0];

        var sampleType, sampleSet;
        var sample = this.getSampleByTime(offset);
        if(sample){
            sampleType = sample.sampleType;
            sampleSet = sample.sampleSet;
        }
        var vol = null;
        //判断note本身有没有hitsound的设定 这里暂时不支持乐器叠加
        var hs = +obj[4];
        var hitsound = null;
        if(hs & 8){
            hitsound = "clap"
        }else if(hs & 4){
            hitsound = "finish";
        }else if(hs & 2){
            hitsound = "whistle";
        }else if(hs & 1){
            hitsound = "normal";
        }else if(hs == 0){
            hitsound = null;
        }
        //判断有没有文件名或者直接的sampleType
        var fn = null;
        if(obj[5]){
            var hitSound = obj[5].split(":");
            if(obj[3] & 128){
                //如果有长条 那第一位作为endTime的要从数组里拿掉
                hitSound = hitSound.slice(1);
            }
            if(hitSound[3] != "0"){
                vol : +hitSound[3];
            }
            if(hitSound[4] && hitSound[4] != "0") {
                fn = hitSound[4].toLowerCase();
                fn = path.basename(fn, path.extname(fn));
            }else{
                if(hitSound[0] != "0"){
                    sampleType = hitSound[0];
                }
                if(hitSound[2] != "0"){
                    sampleSet = hitSound[2];
                }
            }
        }
        if(hitsound || fn){
            if(!fn){
                fn = this.samples[sampleType] + "-hit" + hitsound + sampleSet;
            }
            var realFile = this.fileMapping[fn];
            if(!realFile){
                return null;
            }
            var tid = this.getSampleId(realFile, ret);
            return {realFile:realFile, tid:tid, vol:vol};
        }
        return null;
    },

    getBeat : function(y){
        y = parseInt(y) - this.offset - this.offsetCorrection;
        var beat = Math.floor(y / this.beatLen);
        var subBeat = Math.round((y % this.beatLen) / (this.beatLen / this.divide));
        return [beat, subBeat, this.divide];
    },

    parseMeta: function(filepath){
		var raw = fs.readFileSync(filepath, {encoding:'utf8'});
		if(!raw){
			return null;
		}
		this.dir = path.dirname(filepath);
		var lines = raw.split(/\n|\r\n/g);
		var ret = {};
		this.segment = null;

		if(lines[0].indexOf("osu file format") < 0){
			notify.addNotify({msg:config.i18n("osu01")});
			return ret;
		}

		for(var i=0;i<lines.length;i++){
			var line = lines[i];
			if(line.length == 0 || line.indexOf("//") == 0){
				continue;
			}
			//判断是不是ini段头
			if(/^\[.*?\]/.test(line)){
				this.segment = line.substring(1, line.length-1);
				continue;
			}
			if(this.segment == "General") {
				var pair = this.getValPair(line);
				if(pair[0] == "Mode") {
					var mode = +pair[1];
					if(mode == 3){
						ret.mode = 0;
					}else if(mode == 0 || mode == 2){
						ret.mode = 3;
					}
				}
			}else if(this.segment == "TimingPoints"){
				if(ret.bpm){
					continue;
				}
				var timing = line.split(",");
				ret.bpm = Math.round(60000 / +timing[1]);
			}else if(this.segment == "Metadata"){
				var pair = this.getValPair(line);
				if(pair[0] == "Title"){
					ret.title = pair[1];
				}else if(pair[0] == "Artist"){
					ret.artist = pair[1];
				}else if(pair[0] == "Version"){
					ret.version = pair[1];
				}
			}else if(this.segment == "HitObjects"){
				var obj = line.split(",");
				ret.length = Math.round(+obj[2] / 1000);
			}
		}

		return ret;
	}
};

module.exports = ret;